from django.shortcuts import render
from django.utils import timezone
from django_redis import get_redis_connection
from decimal import Decimal
import json
from django import http
from django.db import transaction

from meiduo_mall.utils.views import LoginRequiredView
from users.models import Address
from goods.models import SKU
from .models import OrderInfo, OrderGoods
from meiduo_mall.utils.response_code import RETCODE
import logging

logger = logging.getLogger('django')


class OrderSettlementView(LoginRequiredView):
    """结算订单"""

    def get(self, request):
        """提供订单结算页面"""
        # 获取登录用户
        user = request.user
        # 查询地址信息
        addresses = Address.objects.filter(user=user, is_deleted=False)

        # 如果地址为空，渲染模板时会判断，并跳转到地址编辑页面
        # addresses = addresses or None

        # 从Redis购物车中查询出被勾选的商品信息
        redis_conn = get_redis_connection('carts')
        redis_cart = redis_conn.hgetall('cart_%s' % user.id)
        cart_selected = redis_conn.smembers('selected_%s' % user.id)
        cart = {}  # 包装购物车中那些勾选商品的sku_id : count
        for sku_id in cart_selected:
            cart[int(sku_id)] = int(redis_cart[sku_id])

        # 准备初始值
        total_count = 0
        total_amount = Decimal('0.00')
        # 查询商品信息
        skus = SKU.objects.filter(id__in=cart.keys())
        for sku in skus:
            sku.count = cart[sku.id]
            sku.amount = sku.count * sku.price
            # 计算总数量和总金额
            total_count += sku.count
            total_amount += sku.amount
        # 补充运费
        freight = Decimal('10.00')

        # 渲染界面
        context = {
            'addresses': addresses,
            'skus': skus,
            'total_count': total_count,
            'total_amount': total_amount,
            'freight': freight,
            'payment_amount': total_amount + freight
        }

        return render(request, 'place_order.html', context)


class OrderCommitView(LoginRequiredView):
    """提交订单"""

    def post(self, request):
        # 接收请求体数据
        json_dict = json.loads(request.body.decode())
        address_id = json_dict.get('address_id')
        pay_method = json_dict.get('pay_method')

        # 校验
        if all([address_id, pay_method]) is False:
            return http.HttpResponseForbidden('缺少必传参数')

        user = request.user
        try:
            address = Address.objects.get(id=address_id, user=user, is_deleted=False)
        except Address.DoesNotExist:
            return http.HttpResponseForbidden('address_id有误')

        # if pay_method not in [1, 2]:
        if pay_method not in [OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
            return http.HttpResponseForbidden('支付方式有误')

        # 生成订单编号: 20200329092000 0000000001  # 日期时间 + user.id
        order_id = timezone.now().strftime('%Y%m%d%H%M%S') + '%09d' % user.id

        # 判断订单初始状态
        # status = 1 if pay_method == 2 else 2
        status = (OrderInfo.ORDER_STATUS_ENUM['UNPAID']
                  if pay_method == OrderInfo.PAY_METHODS_ENUM['ALIPAY']
                  else OrderInfo.ORDER_STATUS_ENUM['UNSEND'])

        # 手动开启事务
        with transaction.atomic():

            # 创建事务保存点
            save_point = transaction.savepoint()

            try:
                # 新增订单基本信息记录(OrderInfo) 一
                order_model = OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    address=address,
                    total_count=0,  # 后期再修改
                    total_amount=Decimal('0.00'),
                    freight=Decimal('10.00'),
                    pay_method=pay_method,
                    status=status
                )
                # 创建redis连接
                redis_cli = get_redis_connection('carts')
                # 获取redis中购物车数据
                redis_dict = redis_cli.hgetall('cart_%s' % user.id)
                selected_ids = redis_cli.smembers('selected_%s' % user.id)
                # 定义一个空字典用来包装要购买商品的sku和count  {sku_id: count}
                cart_dict = {}
                # 过滤只留下勾选的商品id和count
                for sku_id in selected_ids:
                    cart_dict[int(sku_id)] = int(redis_dict[sku_id])

                # 遍历进行商品一个一个下单, 不要用id__in 会有缓存问题,增加数据修改错误风险
                for sku_id in cart_dict:

                    while True:
                        sku = SKU.objects.get(id=sku_id)
                        # 获取当前商品要购买的数量
                        buy_count = cart_dict[sku_id]
                        # 获取sku商品的原库存和销量
                        origin_stock = sku.stock
                        origin_sales = sku.sales

                        # import time
                        # time.sleep(5)  # 暂停5秒
                        # 判断库存
                        if origin_stock < buy_count:
                            # 库存不足,回滚
                            transaction.savepoint_rollback(save_point)
                            return http.JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '%s库存不足' % sku.name})

                        # 修改sku库存和销量
                        new_stock = origin_stock - buy_count
                        new_sales = origin_sales + buy_count
                        # sku.stock = new_stock
                        # sku.sales = new_sales
                        # sku.save()
                        # 0, 1
                        result = SKU.objects.filter(id=sku_id, stock=origin_stock).update(stock=new_stock, sales=new_sales)
                        if result == 0:  # 如果修改库存失败,说明有抢夺
                            continue  # 本次循环后续代码不再执行,直接进行下一次循环
                        # 修改spu销量
                        spu = sku.spu
                        spu.sales += buy_count
                        spu.save()
                        # 新增订单商品信息记录(OrderGoods)  多
                        OrderGoods.objects.create(
                            order_id=order_id,
                            sku=sku,
                            price=sku.price,
                            count=buy_count
                        )

                        # 修改订单中购物车商品总数量
                        order_model.total_count += buy_count
                        # 修改订单中实付金额
                        order_model.total_amount += (sku.price * buy_count)
                        break  # 跳出死循环
                # 累加运费
                order_model.total_amount += order_model.freight
                order_model.save()
            except Exception as e:
                logger.error(e)
                # 暴力回滚
                transaction.savepoint_rollback(save_point)
                return http.JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '提交订单失败'})
            else:
                # 提交事务
                transaction.savepoint_commit(save_point)
        # 将购物车中已提交订单的商品删除
        pl = redis_cli.pipeline()
        pl.hdel('cart_%s' % user.id, *selected_ids)
        pl.delete('selected_%s' % user.id)
        pl.execute()
        # 响应 order_id
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '提交订单成功', 'order_id': order_id})


class OrderSuccessView(LoginRequiredView):
    """展示订单提交成功界面"""
    def get(self, request):

        query_dict = request.GET
        payment_amount = query_dict.get('payment_amount')
        order_id = query_dict.get('order_id')
        pay_method = query_dict.get('pay_method')
        user = request.user
        try:
            OrderInfo.objects.get(total_amount=payment_amount, order_id=order_id, pay_method=pay_method, user=user)
        except OrderInfo.DoesNotExist:
            return http.HttpResponseForbidden('订单有误')

        context = {
            'payment_amount': payment_amount,
            'order_id': order_id,
            'pay_method': pay_method
        }
        return render(request, 'order_success.html', context)